home *** CD-ROM | disk | FTP | other *** search
- /* wrap.c, unwrap.c: wrap and unwrap files with long lines.
- Usage: wrap [-w|-u] [file...]
- Usage: unwrap [-w|-u] [file...]
-
- Wraps the input files by prepending the character START to each line, and
- appending END to the end of the line, or CONT if the following line must
- be appended to it. No wrapped output line is longer than MAXCOL chars.
- If the last line ends with CONT, then there is no '\n' following the
- last line.
- Checksum information is appended for each file.
-
- Unwrap unwraps a file produced by the above command; lines not beginning
- with START are ignored (so mailed wrapped files can be unwrapped, headers
- signatures and all). The checksums are checked for consistency.
-
- Consequently
- wrap file1 file2 | unwrap
- is equivalent to
- cat file1 file2
-
- A filename '-' means standard input.
-
- Flags -w and -u override the program name;
- so "wrap -u" unwraps and "unwrap -w" wraps.
- This is for operating systems that don't support links.
-
- HISTORY:
- LM 910101: original version.
- SP 910215: added -u and -w (for systems with no links)
- added - for stdin
- renamed rindex to standard strrchr
- checked files exist before processing
- handle empty files gracefully when unpacking
- fixed wrap eof bug when input file not newline terminated
- fixed unwrap for multiple files
- SP 910326: rewrite for new format using () (+,
- which protects trailing spaces, and correctly handles files
- that don't end in a newline.
- SP 910905 added -l to give a max line length to wrap (default MAXCOL).
- */
-
- #include <stdio.h>
- extern char *strrchr(), *optarg;
-
- #define separator '/'
-
- #define MAXCOL 80
- #define START '('
- #define END ')'
- #define CONT '+'
- #define CHECK_FRMT "[[wrap saw %d lines, %d chars, %05d hashcode]]\n"
- #define CHECK_ME '['
-
- #define warning(m, v) {fprintf(stderr, "*** %s, file %s, line %d: ",\
- progname, filename, lineno);\
- fprintf(stderr, m, v);}
-
- int htab[128];
-
- init_htab() {
- long r= 1770; int k;
- for (k= 0; k < 128; k++)
- htab[k]= r= (13*r+1)&0x7fff;
- }
-
- #define hashin(h, c) (((((h)<<4)&0x7fff)^((h)>>11))^htab[((h)^(c))&0x7f])
-
- typedef int bool;
-
- #define true 1
- #define false 0
-
- int lineno, lc, cc, hash, maxcol;
- char *filename, *progname;
-
- errmess(f,a) char *f; {
- fprintf(stderr, f, a);
- exit(1);
- }
-
- wrap(fp) FILE *fp; {
- int col=1, ch;
- bool any= false;
-
- newchunk();
- while((ch= readchar(fp)) != EOF) {
- any= true;
- if (col == 1) {
- putchar(START);
- col= 2;
- }
- if (ch == '\n') {
- putchar(END);
- col= 0;
- } else if (col == maxcol) {
- putchar(CONT);
- putchar('\n');
- putchar(START);
- col= 2;
- }
- output(ch); col++;
- }
- if (!any) {
- putchar(START);
- col= 2;
- }
- if (col != 1) {
- putchar(CONT);
- putchar('\n');
- }
- printf(CHECK_FRMT, lc, cc, hash);
- }
-
- bool a_chunk;
-
- unwrap(fp) FILE *fp; {
- a_chunk= false;
- while(chunk(fp)) {}
- if (!a_chunk) {
- warning("no line found beginning %c\n", START);
- }
- }
-
- bool chunk(fp) FILE *fp; {
- newchunk();
- if (skip(fp)) {
- a_chunk= true;
- process(fp);
- check(fp);
- return lookahead(fp) != EOF;
- } else {
- return false;
- }
- }
-
- bool skip(fp) FILE *fp; {
- while(skipline(fp)) {}
- return lookahead(fp) == START;
- }
-
- skipline(fp) FILE *fp; {
- int ch= lookahead(fp);
- if (ch == START || ch == EOF) return false;
- ch= readchar(fp);
- while (ch != '\n' && ch != EOF) ch= readchar(fp);
- return true;
- }
-
- process(fp) FILE *fp; {
- while(copyline(fp)) {}
- }
-
- copyline(fp) FILE *fp; { /* Copy one line; false = EOF or no more lines */
- int ch= readchar(fp); /* Skip the START */
- if (ch == EOF) return false;
- while(copychar(fp)) {}
- return lookahead(fp) == START;
- }
-
- copychar(fp) FILE *fp; { /* Copies characters; false = EOL or EOF */
- int ch= readchar(fp);
- int ch1;
- if (ch == EOF) {
- warning("unexpected end of file\n", 0);
- return false;
- }
- while (ch == END || ch == CONT) {
- ch1= readchar(fp);
- if (ch1 == '\n') {
- if (ch == END) output(ch1);
- return false;
- } else if (ch1 == EOF) {
- warning("unexpected end of file\n", 0);
- return false;
- }
- output(ch);
- ch= ch1;
- }
- if (ch == '\n') {
- warning("newline found not preceded by terminator\n", 0);
- output(ch);
- return false;
- }
- output(ch);
- return true;
- }
-
- int lookahead(fp) FILE *fp; {
- int ch= readchar(fp);
- ungetc(ch, fp);
- return ch;
- }
-
- check(fp) {
- int wlc, wcc, whc;
-
- if ((fscanf(fp, CHECK_FRMT, &wlc, &wcc, &whc)) != 3) {
- warning("was unable to parse the check line %10s ...\n",
- CHECK_FRMT);
- } else {
- if (wlc != lc || wcc != cc || whc != hash) {
- warning("checking error\n", 0);
- fprintf(stderr, "*** Found ");
- fprintf(stderr, CHECK_FRMT, wlc, wcc, whc);
- fprintf(stderr, "*** Had expected ");
- fprintf(stderr, CHECK_FRMT, lc, cc, hash);
- }
- }
- }
-
- newchunk() {
- cc= 0;
- lc= 0;
- hash= 0;
- lineno= 1;
- }
-
- FILE *do_open(name) char *name; {
- FILE *fp;
- if (strcmp(name, "-") == 0) {
- filename= "standard input";
- return stdin;
- }
- filename= name;
- fp= fopen(name, "r");
- if (fp == NULL) {
- warning("can't open %s\n", name);
- }
- return fp;
- }
-
- int readchar(fp) FILE *fp; {
- char ch;
-
- ch= getc(fp);
- if (ch == '\n') lineno++;
- return ch;
- }
-
- output(ch) int ch; {
- cc++;
- if (ch == '\n') {
- lc++;
- }
- hash= hashin(hash, ch);
- putchar(ch);
- }
-
- bool is_wrap(progname) char *progname; {
- char *p= strrchr(progname, separator);
-
- p= p ? p+1 : progname;
- switch (*p) {
- case 'w': return 1;
- case 'u': return 0;
- default: return 1;
- }
- }
-
- main(argc, argv) int argc; char *argv[]; {
- int i, err, do_wrap, c, u, w;
- extern int optind;
- FILE *fp;
-
- progname= argv[0];
- filename= "standard input";
-
- if (CHECK_ME != *CHECK_FRMT)
- errmess("*** ERROR 666@#$?!FUBAR -- unauthorised mod to program\n", 0);
-
- if (sizeof(int) < 2) {
- warning("your machine's ints are too short (%d bytes);\n",
- (int)(sizeof(int)));
- warning("this may cause spurious warnings by unwrap\n", 0);
- }
-
- init_htab();
-
- do_wrap= is_wrap(progname);
-
- /* Process flags */
- err=0; u=0; w=0; maxcol= MAXCOL;
- while ((c= getopt(argc, argv, "uwl:")) != -1) {
- switch (c) {
- case 'u': u=1; do_wrap=0; break;
- case 'w': w=1; do_wrap=1; break;
- case 'l': maxcol= atoi(optarg);
- if (maxcol<3) {
- errmess("Line length must be > 2\n", "");
- exit(1);
- }
- break;
- case '?': err=1; break;
- }
- }
-
- if (err || (u == 1 && w == 1)) {
- errmess("Usage: %s [-w|-u|-l length] [file...]\n", argv[0]);
- }
-
- /* Check file arguments */
- err= 0;
- for (i=optind; i<argc; i++) {
- if ((fp= do_open(argv[i])) == NULL) {
- err=1;
- } else fclose(fp);
- }
- if (err) exit(1);
-
- if (do_wrap) {
- printf("This is a wrapped file. ");
- printf("Pipe it through 'unwrap', or edit it by hand:\n");
- printf(" delete all lines that do not begin with %c\n", START);
- printf(" delete the leading %c on all other lines\n", START);
- printf(" delete all trailing %c's\n", END);
- printf(" delete all trailing %c's, and append the following line\n", CONT);
- }
-
- if (argc == optind) { /* No file arguments */
- if (do_wrap) wrap(stdin);
- else unwrap(stdin);
- } else {
- for (i=optind; i<argc; i++) {
- if (strcmp(argv[i], "-") == 0) {
- if (do_wrap) wrap(stdin);
- else unwrap(stdin);
- } else if ((fp= do_open(argv[i], "r")) == NULL) {
- exit(1);
- } else {
- if (do_wrap) wrap(fp);
- else unwrap(fp);
- fclose(fp);
- }
- }
- }
- exit(0);
- }
-